﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TinyCms.Core.Repositories
{
    public abstract class RepositoryContext:DisposableObject,IRepositoryContext
    {
        #region Private Fields
        private readonly Guid _id = Guid.NewGuid();
        private readonly Dictionary<Guid, object> _newCollection = new Dictionary<Guid, object>();
        private readonly Dictionary<Guid, object> _modifiedCollection = new Dictionary<Guid, object>();
        private readonly Dictionary<Guid, object> _deletedCollection = new Dictionary<Guid, object>();
        private bool _committed = true;
        #endregion

        #region Protected Methods
        /// <summary>
        /// Clears all the registration in the repository context.
        /// </summary>
        /// <remarks>Note that this can only be called after the repository context has successfully committed.</remarks>
        protected void ClearRegistrations()
        {
            _newCollection.Clear();
            _modifiedCollection.Clear();
            _deletedCollection.Clear();
        }
        #endregion

        #region Protected Properties
        /// <summary>
        /// 获取所有将被持久化到数据库的对象
        /// </summary>
        protected IEnumerable<KeyValuePair<Guid, object>> NewCollection
        {
            get { return _newCollection; }
        }
        /// <summary>
        /// 获取所有将被更新到数据的对象
        /// </summary>
        protected IEnumerable<KeyValuePair<Guid, object>> ModifiedCollection
        {
            get { return _modifiedCollection; }
        }
        /// <summary>
        /// 获取所有将被从数据库删除的对象
        /// </summary>
        protected IEnumerable<KeyValuePair<Guid, object>> DeletedCollection
        {
            get { return _deletedCollection; }
        }
        #endregion



        public Guid ID
        {
            get { return _id; }
        }

        public virtual void RegisterNew<T>(T obj) where T : EntityBase
        {
            if (obj.ID.Equals(Guid.Empty))
                throw new ArgumentException("对象的ID为空", "obj");
            if (_modifiedCollection.ContainsKey(obj.ID))
                throw new InvalidOperationException("该对象已被标识为已修改");
            if (_newCollection.ContainsKey(obj.ID))
                throw new InvalidOperationException("该对象已被添加");
            _newCollection.Add(obj.ID, obj);
            _committed = false;
        }

        public virtual void RegisterModified<T>(T obj) where T : EntityBase
        {
            if (obj.ID.Equals(Guid.Empty))
                throw new ArgumentException("对象的ID为空", "obj");
            if (_deletedCollection.ContainsKey(obj.ID))
                throw new InvalidOperationException("该对象已被标识为已删除");
            if (!_modifiedCollection.ContainsKey(obj.ID) && !_newCollection.ContainsKey(obj.ID))
                _modifiedCollection.Add(obj.ID, obj);
            _committed = false;
        }

        public virtual void RegisterDeleted<T>(T obj) where T : EntityBase
        {
            if (obj.ID.Equals(Guid.Empty))
                throw new ArgumentException("对象的ID为空", "obj");
            if (_newCollection.ContainsKey(obj.ID))
            {
                if (_newCollection.Remove(obj.ID))
                    return;
            }
            bool removedFromModified = _modifiedCollection.Remove(obj.ID);
            bool addedToDeleted = false;
            if (!_deletedCollection.ContainsKey(obj.ID))
            {
                _deletedCollection.Add(obj.ID, obj);
                addedToDeleted = true;
            }
            _committed = !(removedFromModified || addedToDeleted);
        }

        public bool Committed
        {
            get { return _committed; }
            set { _committed = value; }
        }

#region 抽象
//此处还未知继承的上下文，所以将事务的实现留给派生类实现        
        public abstract void Commit();

        public abstract void Rollback();
#endregion
    }
}
